#pragma once

/********************************EXAMPLES*******************************************************
*                          For a rooms data node as:
*	-node:
*		-room[0]
*			-user[0]
*				-username :  "user1"
*				-userid   :  100001(int32)
*			-user[1]
*				-username :  "user2"
*				-userid   :  100002(int32)
		

*Case 1 : If you want send a packet for above node.You can write code like this:


	GLBlockTree root;
	BlockNode* room1node = root.AddChild(ROOM_KEY);
	room1node->AddChild(USER_KEY)->AddChild(USERID_KEY)->SetInt(100001);
	room1node->GetBackChild()->AddChild(USERNAME_KEY)->SetString("user1);

	room1node->AddChild(USER_KEY)->AddChild(USERID_KEY)->SetInt(100002);
	room1node->GetBackChild()->AddChild(USERNAME_KEY)->SetString("user2");

*                             Then use the tree to make a netpacket	

	ByteBuffer pack;
	root.FillUpNetPacket(pack);
	// send it

*Case 2 : Else if you want use this node from a received network packet.You can write code like this:

	//supposed has received a ByteBuffer named pack

	//1.creat tree,use LoadFromNetPacket to fill the tree
	GLBlockTree tree2;
	tree2.LoadFromNetPacket(pack);

	//2.traverse the tree's every node
	NodeIterator itroom;
	BlockNode *tmproomnode = tree2.FindFirstChild(ROOM_KEY,itroom);
	while(tmproomnode != NULL)
	{
		cout<<"-room"<<endl;
		NodeIterator ituser;
		BlockNode *tmpusernode = tmproomnode->FindFirstChild(USER_KEY, ituser);

		while( tmpusernode != NULL )
		{
		cout<<"	-user"
			BlockNode *tmpuserIdnode = tmpusernode->FindChild(USERID_KEY);
			BlockNode *tmpuserNamenode = tmpusernode->FindChild(USERNAME_KEY);
			if(tmpuserNamenode != NULL)
				cout<<"		-"<<tmpuserNamenode->GetString()<<endl;
			if(tmpuserIdnode != NULL)
				cout<<"		-"<<tmpuserIdnode->GetInt()<<endl;
			tmpusernode = tmproomnode->FindNextChild(USER_KEY, ituser);
		}
		
		tmproomnode = tree2.FindNextChild(ROOM_KEY,itroom);
	}


//the result will be:
-room
	-user
		user1
		100001
	-user
		user2
		100002
	
********************************************END**************************************************/

#include "byteBuffer.h"

enum
{
	KEY_ROOT	  =	0x0000,
	NULL_KEY 	  =	0xFFFF,
};

enum NodeType
{
	TYPE_BLOCK    = 0x00,
	TYPE_INT8     = 0x01,
	TYPE_INT16    = 0x02,
	TYPE_INT32    = 0x03,
	TYPE_DOUBLE   = 0x04, 
	TYPE_INT64    = 0x05,
	TYPE_STRING   = 0x06
};

class BlockNode;
typedef vector<BlockNode*>::const_iterator NodeIterator; //for next node

class BlockNode 
{
public:

	BlockNode(uint16 key, BlockNode* parent):_key(key),_parent(parent),_type(TYPE_BLOCK){};
	~BlockNode();

public:

	uint16 GetKey()const { return _key; }
	void SetKey(uint16 key){_key = key;}

	uint8 GetType()const {return _type;}

	char  GetChar() const;
	short GetShort() const;
	int   GetInt() const;
	int64 GetInt64() const;
	double GetDouble() const;
	string GetString() const;
	
	void SetChar(char value);
	void SetShort(int16 value );
	void SetInt(int value);
	void SetInt64(int64 value);
	void SetDouble(double value);
	void SetString(const string& value);

public:

	bool IsEmpty() const;

	BlockNode* GetParent() const;

	bool HasChild() const;

	BlockNode* AddChild(uint16 key = NULL_KEY);

	BlockNode* GetFirstChild(NodeIterator& iter) const;
	BlockNode* GetNextChild(NodeIterator& iter) const;
	BlockNode* GetChild(NodeIterator iter) const;
	BlockNode* GetBackChild() const;

	BlockNode* FindFirstChild(uint16 key, NodeIterator& iter) const;
	BlockNode* FindNextChild(uint16 key, NodeIterator& iter) const;
	void ClearChild();

protected:

	uint16 _key;
	BlockNode* _parent;
	uint8 _type;
	string m_data;
	vector<BlockNode*> _children;

protected:	

	int16 Tree2Packet(ByteBuffer& pack);
	bool CreatTreeFromPacket(ByteBuffer& pack, uint16& parsed_len, bool is_root=true);
};

class BlockTree : public BlockNode
{
public:

	BlockTree();
	bool LoadFromNetPacket(ByteBuffer& pack);
	bool FillUpNetPacket(ByteBuffer& pack);
};

class BlockNodeException : public Exception
{
public:

	BlockNodeException(string description) : Exception(description) {}
	virtual ~BlockNodeException() {}
};